#include "stdafx.h"
#include "Message.h"
#include "MessageFactory.h"
#include "gamebutton.h"
#include "galcon.h"
#include "PlanetInternalImpl.h"
#include "PlayerInternalImpl.h"
#include <QMessageBox>

const int countOfPlanets = 10;
const int countOfPlayers = 2;

galcon::galcon(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
{
   ui.setupUi(this);
   init();
}

galcon::~galcon()
{
   disconnectSignals();
}

void fillGameInitInfo(GameInitInfoPtr& gameInfo)
{
   PlanetsInitInfoVector planetsInitInfo;
   
   PlanetInternalImplPtr currentPlanet;
   double xCoord;
   double yCoord;
   PlanetID planetID;
   PlanetSize planetSize;

   for (unsigned int i = 0; i < countOfPlanets; ++i)
   {
      xCoord = (double)qrand() / RAND_MAX;
      yCoord = (double)qrand() / RAND_MAX;
      planetID = PlanetID(i);
      planetSize = PlanetSize(i % countOfPlanetsSize);
      currentPlanet = boost::make_shared<PlanetInternalImpl>(planetID, 0, undefinedPlayerID, xCoord, yCoord,  planetSize);
      planetsInitInfo.push_back(currentPlanet);
   }

   PlayersInitInfoVector playersInitInfo;

   PlayerInternalImplPtr currentPlayer;
   GameColors currentColor;
   PlayerID playerID;

   for (unsigned int i = 0; i < countOfPlayers; ++i)
   {
      currentColor = GameColors(i);
      playerID = PlayerID(0);
      currentPlayer = boost::make_shared<PlayerInternalImpl>(playerID, currentColor);
      playersInitInfo.push_back(currentPlayer);
      planetsInitInfo[i]->SetPlayerID(playerID);
   }
   
   gameInfo = boost::make_shared<GameInitInfo>(PlayerID(0), planetsInitInfo, playersInitInfo);
}

void galcon::init()
{
   m_mainGraphicsView.reset(ui.m_gameGraphicsView);
   m_mainGraphicsView->setRenderHint(QPainter::Antialiasing);
   m_mainGraphicsView->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
   initMainMenu();
}

void galcon::scaleView( qreal scaleFactor )
{
   qreal factor = ui.m_gameGraphicsView->transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
   if (factor < 0.5 || factor > 4)
      return;

   ui.m_gameGraphicsView->scale(scaleFactor, scaleFactor);
}

void galcon::keyPressEvent( QKeyEvent *event )
{
   switch (event->key())
   {
   case Qt::Key_Plus:
         scaleView(1.2);
      break;
   case Qt::Key_Minus:
         scaleView(1/1.2);
      break;
   default:
      break;
   }
}

void galcon::disconnectSignals()
{
   qDebug() << "galcon destructor";
   disconnect();
   dumpObjectInfo();
}

void galcon::initMainMenu()
{
   m_mainMenu = boost::make_shared<MainMenu>();
   m_mainMenu->setItemIndexMethod(QGraphicsScene::NoIndex);
   m_mainMenu->setSceneRect(0,0,SceneRectWidth,SceneRectHeight);
   m_mainGraphicsView->setScene(m_mainMenu.get());
   m_mainMenu->update();
   QObject::connect(m_mainMenu->StartLocalGameBtn().get(), SIGNAL(clicked()), this, SLOT(startLocalGame()));
   QObject::connect(m_mainMenu->StartLanGameBtn().get(), SIGNAL(clicked()), this, SLOT(startLANGame()));
   QObject::connect(m_mainMenu->QuitGameBtn().get(), SIGNAL(clicked()), QCoreApplication::instance(), SLOT(quit()));
}

void galcon::startLocalGame()
{
   GameInitInfoPtr gameInitInfo;
   fillGameInitInfo(gameInitInfo);
   m_game = boost::make_shared<Game>(m_mainGraphicsView, gameInitInfo);
   m_game->StartLocalGame();
}

void galcon::startLANGame()
{
   if (!m_game)
   {
      qRegisterMetaType<Message>("Message");
      m_game = boost::make_shared<Game>(m_mainGraphicsView);
      QObject::connect(this, SIGNAL(newMessageRecieved(const Message&)), this, SLOT(handleMessage(const Message&)));
      QObject::connect(m_game.get(), SIGNAL(SendMessage(const Message&)), this, SLOT(onSendNewMessageHandler(const Message&)));
      QObject::connect(&m_hostnameSelectDlg, SIGNAL(tryToConnect()), this, SLOT(connectToHost()));
      m_client.reset(new GalconClient(m_hostnameSelectDlg.GetAddress(), m_hostnameSelectDlg.GetPort(),
         boost::bind(&galcon::onConnectFailedHandler, this, _1),
         boost::bind(&galcon::onNewMessageHandler, this, _1)));
      m_messageFactory = boost::make_shared<MessageFactory>(m_client, m_game, m_mainGraphicsView);
   }
   m_hostnameSelectDlg.exec();
}

void galcon::onConnectFailedHandler( const Message& newMessage )
{
   emit newMessageRecieved(newMessage);
   Sleep(0);
}

void galcon::onNewMessageHandler( const Message& newMessage )
{
   qDebug() << "Game::onNewMessageHandler" << GetCurrentThreadId();
   qDebug() << QString(newMessage.GetBody());
   emit newMessageRecieved(newMessage);
   Sleep(0);
}

void galcon::connectToHost()
{
   qDebug() << "Game::connectToHost" << GetCurrentThreadId();
   m_client->Connect();
}

void galcon::handleMessage( const Message& messagePr )
{
   try
   {
      MessageBasePtr messagePtr = m_messageFactory->ParseMessage(messagePr);
      messagePtr->Execute();
   }
   catch (const std::exception& e)
   {
      QString message("Error occurred: ");
      message.append(e.what());
      QMessageBox::information(this, "Error", message, QMessageBox::Ok);
   }
}

void galcon::onSendNewMessageHandler( const Message& newMessage )
{
   try
   {
      m_client->Send(newMessage);
   }
   catch (const std::exception& e)
   {
      QString message("Error occurred: ");
      message.append(e.what());
      QMessageBox::information(this, "Error", message, QMessageBox::Ok);
   }
}